﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace RFSwitchArray
{
    public delegate void EXChangeEventHandler(object sender, RFSAEventArgs e);

    public class CRFSwitchArray :IRFSwitchArray
    {
        public CRFSwitchArray()         
        {
        }
        #region - 全局变量--------------------------------------------------------------------------
  
        private List<int> InPortList = new List<int>() { 0, 1 };

        private List<int> OutPortList = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

        private int InPortIndex = 0;  

        private int OutPortIndex = 0;
        
        private byte[] CHW0 = new byte[] { 0X01, 0X02, 0X03, 0X04, 0X05, 0X06, 0X07, 0X08, 0X09, 0X0A, 0X0B, 0X0C, 0X00 };

        private byte[] CHW1 = new byte[] { 0X41, 0X42, 0X43, 0X44, 0X45, 0X46, 0X47, 0X48, 0X49, 0X4A, 0X4B, 0X4C };

        private byte[] CHR = new byte[2] { 0X81, 0XC1};

        private byte[] msg = new byte[13] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0 };

        private byte databuf;

        List<bool> fd;

        public System.IO.Ports.SerialPort sp;

        public struct SwitchArrayAttribute
        {
            public string Model;
            public string SN;
            public string Manufactory;
            public int InPortNumber;
            public int OutPortNumber;
            public int InPortStartIndex;
            public int OutPortStratIndex;
            public int StartFrequeny;
            public int StopFrequency;
            public int ExchangeTime;

        }

        /// <summary>
        /// SerialPort使能标志位
        /// </summary>
        private bool _Enabled = true;
        public bool Enabled
        {
            get { return _Enabled; }
            set { _Enabled = value; }
        }
        #endregion


        #region - 华芯微波-产品信息-----------------------------------------------------------------
        /// <summary>
        /// 型号
        /// </summary>
        private string _Model = "HX213KGGF2581G";        
        public string Model 
        {
            get { return _Model; }
        }

        /// <summary>
        /// 系列号
        /// </summary>
        private string _SN = "0001";
        public string SN 
        {
            get { return _SN; }
        }
        

        /// <summary>
        /// 厂家名称
        /// </summary>
        private string _Manufactory="华芯微波";
        public string Manufactory 
        {
            get { return _Manufactory; }
        }

        /// <summary>
        /// 输入端口数量。value=2;
        /// </summary>  
        private int _InPortNumber = 2;
        public int InPortNumber
        {
            get { return _InPortNumber; }
        }
        

        /// <summary>
        /// 输出端口数量。value=13;
        /// </summary>
        private int _OutPortNumber = 13;
        public int OutPortNumber
        {
            get { return _OutPortNumber; }
        }
        

        /// <summary>
        /// 输入端口起始索引。通常为0或1。应用程序要按照此索引起始值对端口进行访问。
        /// 0代表CH1，CAL为CH12.
        /// </summary>
        private int _InPortStartIndex=0;
        public int InPortStartIndex 
        {
            get { return _InPortStartIndex; }
        }

        /// <summary>
        /// 输出端口起始索引。通常为0或1。应用程序要按照此索引起始值对端口进行访问。
        /// </summary>
        private int _OutPortStartIndex=0;
        public int OutPortStartIndex 
        {
            get { return _OutPortStartIndex; }
        }

        /// <summary>
        /// 起始工作频率，单位：MHz。
        /// </summary>
        private int _StartFrequeny=700;
        public int StartFrequeny 
        {
            get { return _StartFrequeny; }
        }

        /// <summary>
        /// 终止工作频率，单位：MHz。
        /// </summary>
        private int _StopFrequeny=4000;
        public int StopFrequeny 
        {
            get { return _StopFrequeny; }
        }

        /// <summary>
        /// 通道切换时间。单位：ms。
        /// </summary>
        private int _ExchangeTime;
        public int ExchangeTime
        {
            get { return _ExchangeTime; }
        }

        #endregion


        #region - 事件------------------------------------------------------------------------------

        /// <summary>
        /// SerialPort接收处理事件，下位机有cmd响应就触发该事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) 
        {
           databuf=(byte)sp.ReadByte();
           //debugbuf = databuf;
        }

        /// <summary>
        /// 切换完成后启动此事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ExchangeComplete_Event(object sender, RFSAEventArgs e) 
        {
           // Console.WriteLine(RFSAEventArgs.RFSAError.NoError.ToString());
            MessageBox.Show(RFSAEventArgs.RFSAError.NoError.ToString());
        }

        /// <summary>
        /// 切换发生错误时启动此事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ExchangeError_Event(object sender,RFSAEventArgs e) 
        {
            MessageBox.Show(RFSAEventArgs.RFSAError.CommError.ToString());
        }
        #endregion

        /// <summary>
        ///  反回输入口索引所指示的输入口到输出口索引所指示的输出口是否具有连通能力。
        /// </summary>
        /// <param name="InPortIndex">输入口索引，0~InputPortNumber-1</param>
        /// <param name="OutPortIndex">输出口索引，0~InputPortNumber-1</param>
        /// <returns>返回是否具有连通能力，True：有；False:无</returns>
        public bool FeedThroughAbility(int InPortIndex, int OutPortIndex)
        {
            try
            {
                if (InPortIndex == InPortList[0] && OutPortIndex >= OutPortList[0] && OutPortIndex <= OutPortList[12])
                {
                    return true;
                }
                else if (InPortIndex == InPortList[1] && OutPortIndex >= OutPortList[0] && OutPortIndex <= OutPortList[11])
                {
                    return true;
                }
                else return false;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }
        }

        /// <summary>
        /// 返回指定的输入口与所列输出口的是否能够连通
        /// </summary>
        /// <param name="InportIndex">输入口索引，0~InputPortNumber</param>       
        public List<bool> FeedThroughAbility(int InPortIndex) 
        {
            Dictionary<int, List<bool>> feed1 = new Dictionary<int, List<bool>>();
            feed1.Add(0, new List<bool> { true, true, true, true, true, true, true, true, true, true, true, true, true });
            feed1.Add(1, new List<bool> { true, true, true, true, true, true, true, true, true, true, true, true, false });
            foreach (var i in feed1)
            {
                if (i.Key.Equals(InPortIndex)) 
                {
                   fd=i.Value;
                }
            }
            return fd;         
        }


          #region - 方法------------------------------------------------------------------------------
          /// <summary>
          /// 必要时用此命令完成开关阵的初始化工作
          /// </summary>
          public void RFSwitchInit(string mPortName)
          {
              if (Enabled == true)   //使用时需要把Enabled属性设置为true,初始化为null.
              {
                  sp = new SerialPort();
                  sp.WriteTimeout = 1000;
                  sp.ReadTimeout = 5000;
                  //   sp.NewLine = "\r\n";
                  sp.PortName = mPortName;
                  sp.BaudRate = 115200;
                  sp.DataBits = 8;
                  sp.Parity = Parity.None;
                  sp.StopBits = StopBits.One;
                  sp.RtsEnable = true;
                  
                  try
                  {
                      if (sp.IsOpen)
                      {                         
                          sp.Close();
                      }
                      sp.Open();
                      //sp.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
                  }
                  catch
                  {
                  }
              }
          }

          /// <summary>
          /// 命令同步将指定的输入口与指定的输出口连通。要保证切换完成，通道能够正常传输型号再返回。
          /// </summary>
          /// <param name="InPortIndex">输入口索引</param>
          /// <param name="OutPortIndex">输出口索引</param>
          public void SyncExchange(int InPortIndex, int OutPortIndex)  //inport:0,outport:4
          {
              _ExchangeComplete = false;    //切换标志位置0
              System.Threading.Thread.Sleep(0);
             // sp.ReadTimeout = 5000;
              try
              {
                  if (InPortIndex == InPortList[0]) //判断输入口为0
                  {
                      int i = OutPortList[OutPortIndex];
                      sp.Write(CHW0, OutPortList[OutPortIndex], 1);
                      delay(5);
                      sp.Write(CHR, 0, 1);     //查询连接状态
                      delay(5);
                      databuf = (byte)sp.ReadByte();//同步读取一个字节
                      if (msg[OutPortIndex] == databuf)
                      {
                        //  sp.DiscardInBuffer();
                          _ExchangeComplete = true;          
                      }
                  }
                  else if (InPortIndex == InPortList[1])
                  {
                      sp.Write(CHW1, OutPortList[OutPortIndex], 1);
                      //delay
                      delay(5);
                      sp.Write(CHR, 1, 1);
                      delay(5);
                      databuf = (byte)sp.ReadByte();
                      if (msg[OutPortIndex] == databuf)
                      {
                          _ExchangeComplete = true;
                      }
                  }
                  else _ExchangeComplete = false;
              }
              catch
              {
              }
          }

          /// <summary>
          /// 命令同步将指定的输入口与指定的输出口连通。要保证切换完成，通道能够正常传输型号再返回。
          /// 一次可以命令多对连通口。其中Key代表输入口索引。Value代表输出口索引
          /// </summary>
          /// <param name="InOutPortIndexs">输入口索引与输出口索引表</param>
          /// 如果索引超出范围，则应抛出“索引超出范围错误”
          public void SyncExchange(Dictionary<int, int> InOutPortIndexs)
          {
              _ExchangeComplete = false;    //切换标志位置0
              System.Threading.Thread.Sleep(0);
              //  sp.WriteTimeout = 1000;
              sp.ReadTimeout = 5000;
              try
              {
                  InOutPortIndexs.Add(InPortList[InPortIndex], OutPortList[OutPortIndex]);
                  if (InOutPortIndexs[InPortList[InPortIndex]] == 0)
                  {
                      sp.Write(CHW0, OutPortList[OutPortIndex], 1);
                      //delay   电子开关为260ns
                      delay(5);
                      sp.Write(CHR, 0, 1);     //查询连接状态
                      delay(5);
                      databuf = Convert.ToByte(sp.ReadByte());//同步读取一个字节
                      if (msg[OutPortIndex] == databuf)
                      {
                          _ExchangeComplete = true;
                      }
                      else _ExchangeComplete = false;
                  }
                  else if (InOutPortIndexs[InPortList[InPortIndex]] == 1)  //key==1
                  {
                      sp.Write(CHW1, OutPortList[OutPortIndex], 1);
                      //delay
                      delay(5);
                      sp.Write(CHR, 1, 1);
                      delay(5);
                      databuf = (byte)sp.ReadByte();
                      if (msg[OutPortIndex] == databuf)
                      {
                          _ExchangeComplete = true;
                      }
                      else _ExchangeComplete = false;
                  }
                  else _ExchangeComplete = false;
              }
              catch
              {
              }

          }

          /// <summary>
          /// 命令异步将指定的输入口与指定的输出口连通。此命令应尽快做完必要设置工作后马上返回，不必等到切换完成。 切换完成的信息应由其它途径得到。
          /// </summary>
          /// <param name="InPortIndex">输入口索引</param>
          /// <param name="OutPortIndex">输出口索引</param>
          /// 命令异步将指定的输入口与指定的输出口连通。此命令应尽快做完必要设置工作后马上返回，不必等到切换完成。 切换完成的信息应由其它途径得到。
          public void AsynExchange(int InPortIndex, int OutPortIndex)
          {
              _ExchangeComplete = false;    //切换标志位置0
              try
              {
                  if (InPortIndex == InPortList[0])
                  {
                      sp.Write(CHW0, OutPortList[OutPortIndex], 1);
                      _ExchangeComplete = true;
                  }
                  else if (InPortIndex == InPortList[1])
                  {
                      sp.Write(CHW1, OutPortList[OutPortIndex], 1);
                      _ExchangeComplete = true;
                  }
                  else _ExchangeComplete = false;
              }
              catch { }
          }

          /// <summary>
          /// 命令异步将指定的输入口与指定的输出口连通。即此命令应尽快做完必要设置工作后马上返回，不必等到切换完成。 切换完成的信息由其它途径得到。
          /// 一次可以命令多对连通口。其中Key代表输入口索引。Value代表输出口索引
          /// </summary>
          /// <param name="InOutPortIndex">输入口索引与输出口索引表</param>
          /// 如果索引超出范围，则应抛出“索引超出范围错误”
          public void AsynExchange(Dictionary<int, int> InOutPortIndex) 
          {
              _ExchangeComplete = false;    //切换标志位置0
              try
              {
                  InOutPortIndex.Add(InPortList[InPortIndex],OutPortList[OutPortIndex]);
                  if (InOutPortIndex[InPortList[InPortIndex]] == 0)
                  {
                      sp.Write(CHW0, OutPortList[OutPortIndex], 1);
                      _ExchangeComplete = true;
                  }
                  else if (InOutPortIndex[InPortList[InPortIndex]] == 1)
                  {
                      sp.Write(CHW1, OutPortList[OutPortIndex], 1);
                      _ExchangeComplete = true;
                  }
                  else _ExchangeComplete = false;
              }
              catch 
              {
 
              }
          }

          #region - 状态------------------------------------------------------------------


          
          /// <summary>
          /// 指示是否已经完成切换。驱动软件应在收到切换命令后立即置此值为fale。待确定完成切换后再置true。
          /// </summary>
          public bool ExchangeComplete
          {
              get { return _ExchangeComplete; }
          }
          private bool _ExchangeComplete;

        

          /// <summary>
          /// 返回指定的输入口与哪一输出口连通。如果开路，则返回-1。
          /// </summary>
          /// <param name="InPortIndex">输入口索引</param>
          /// <returns>输出口索引</returns>        
          public int InPortThroughTo(int InPortIndex)
          {
              try
              {
                  if (InPortIndex == InPortList[0])
                  {
                      sp.DiscardInBuffer();
                      sp.Write(CHR, 0, 1);   //写CHR 0X81进行读
                      //延时
                      System.Threading.Thread.Sleep(10);
                      switch ((int)databuf)  //databuf,输出DEC
                      {
                          case 0:
                              OutPortIndex = OutPortList[12];
                              break;
                          case 1:
                              OutPortIndex = OutPortList[0];
                              break;
                          case 2:
                              OutPortIndex = OutPortList[1];
                              break;
                          case 3:
                              OutPortIndex = OutPortList[2];
                              break;
                          case 4:
                              OutPortIndex = OutPortList[3];
                              break;
                          case 5:
                              OutPortIndex = OutPortList[4];
                              break;
                          case 6:
                              OutPortIndex = OutPortList[5];
                              break;
                          case 7:
                              OutPortIndex = OutPortList[6];
                              break;
                          case 8:
                              OutPortIndex = OutPortList[7];
                              break;
                          case 9:
                              OutPortIndex = OutPortList[8];
                              break;
                          case 10:
                              OutPortIndex = OutPortList[9];
                              break;
                          case 11:
                              OutPortIndex = OutPortList[10];
                              break;
                          case 12:
                              OutPortIndex = OutPortList[11];
                              break;
                          default:
                              OutPortIndex = -1;
                              break;
                      }
                      //  sp.DiscardInBuffer();
                      return OutPortIndex;
                  }
                  else if (InPortIndex == InPortList[1])
                  {
                      sp.Write(CHR, 1, 1);
                     // delay(5);
                      System.Threading.Thread.Sleep(10);
                      switch ((int)databuf)
                      {
                          case 1:
                              OutPortIndex = OutPortList[0];
                              break;
                          case 2:
                              OutPortIndex = OutPortList[1];
                              break;
                          case 3:
                              OutPortIndex = OutPortList[2];
                              break;
                          case 4:
                              OutPortIndex = OutPortList[3];
                              break;
                          case 5:
                              OutPortIndex = OutPortList[4];
                              break;
                          case 6:
                              OutPortIndex = OutPortList[5];
                              break;
                          case 7:
                              OutPortIndex = OutPortList[6];
                              break;
                          case 8:
                              OutPortIndex = OutPortList[7];
                              break;
                          case 9:
                              OutPortIndex = OutPortList[8];
                              break;
                          case 10:
                              OutPortIndex = OutPortList[9];
                              break;
                          case 11:
                              OutPortIndex = OutPortList[10];
                              break;
                          case 12:
                              OutPortIndex = OutPortList[11];
                              break;
                          default:
                              OutPortIndex = -1;
                              break;
                      }
                      return OutPortIndex;
                  }
                  else
                      return OutPortIndex = -1;
              }
              catch 
              {
                  return OutPortIndex = -1;
              }
          }

          /// <summary>
          /// 返回索引指定的输出口与哪一输入口连通。如果开路，则返回-1。
          /// </summary>
          /// <param name="OutPortIndex">输出口索引</param>
          /// <returns>输入口索引</returns>
          public int OutPortThroughTo(int OutPortIndex)  //查CH12
          {
              try
              {
                  int i;
                  for (i = 0; i < 2; i++)
                  {
                      sp.Write(CHR, i, 1);
                      System.Threading.Thread.Sleep(10);
                      int c = Convert.ToInt32(databuf);  //HEX:0X0A，DEC:c=10                  
                      if (msg[OutPortIndex] == c)     //msg[12]=0  c=0
                      {
                          return i;
                      }
                  }
                  return -1;
              }
              catch 
              {
                  return -1;
              }
          }


          #endregion

          #endregion
        /// <summary>
        /// (新增)返回通道组通道数量
        /// </summary>
        public int ChannelNumber 
        {
            get { return _ChannelNumber; }
        }
        private int _ChannelNumber;

        /// <summary>
        /// (新增)返回当前通道组指针
        /// </summary>
        public int ChannelPoint
        {
            get{return _ChannelPoint;}
        }
        private int _ChannelPoint;
   

        /// <summary>
        /// 必要时用此命令完成开关阵的初始化工作
        /// </summary>

        //调用API函数
        [DllImport("kernel32.dll")]
        extern static short QueryPerformanceCounter(ref long x);
        [DllImport("kernel32.dll")]
        extern static short QueryPerformanceFrequency(ref long x);

        /// <summary>
        /// （新增）微秒delay
        /// </summary>
        /// <param name="delay_Time"></param>
        public void delay(long delay_Time) 
        {
            long stop_Value = 0;
            long start_Value = 0;
            long freq = 0;
            long n = 0;

            QueryPerformanceFrequency(ref freq);
            long count = delay_Time * freq / 1000000;     
            //  1000HZ =1秒10000次
            QueryPerformanceCounter(ref start_Value);

            while (n < count) 
            {
                QueryPerformanceCounter(ref stop_Value);   
                n = stop_Value - start_Value;  
            }
        }

    }

    public class RFSAEventArgs : EventArgs
    {
        public enum RFSAError
        {
            //无错误
            NoError = 0,
            //通讯错误
            CommError = 1,
            //操作超时
            CommTimeOver = 2,
            //输入口索引超出范围
            InPortIndexOverranging = 3,
            //输出口索引超出范围
            OutPortIndexOverranging = 4
        };

        /// <summary>
        /// 完成连通的输入口索引。如果是组合切换完成事件，则此值为-1
        /// </summary>
        public int InPortIndex;
        /// <summary>
        /// 完成连通的输出口索引。如果是组合切换完成事件，则此值为-1
        /// </summary>
        public int OutPortIndex;
        /// <summary>
        /// 完成组合切换中各连通口索引。键（Key）表示输入口索引，值（Value）表示输出口索引
        /// </summary>
        public Dictionary<int, int> InOutPair;
        /// <summary>
        /// 错误类型。见错误类型枚举中的说明
        /// </summary>
        public RFSAError ErrorType;
    }
}
